﻿using Framework.LogServices.Models;
using System.Collections.Concurrent;

namespace Framework.LogServices
{
    /// <summary>
    /// 本地文件日志记录
    /// </summary>
    public static class LocalLoggingFile
    {
        private static readonly string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "kafkaLog");
        private static string filePath = Path.Combine(basePath, $"{DateTime.Now:yyyyMMddHHmmss}");
        private static readonly ConcurrentQueue<LogEntry> logQueue = new ConcurrentQueue<LogEntry>();
        private static readonly SemaphoreSlim logSignal = new SemaphoreSlim(0);
        private static readonly CancellationTokenSource cts = new CancellationTokenSource();
        private static readonly ConcurrentDictionary<string, byte> pwIdInfo = new ConcurrentDictionary<string, byte>();
        private static volatile bool isProcessing = true;
        private static readonly object flushLock = new object();
        private static int activeConsumers = 0;

        /// <summary>
        /// 本地文件日志记录
        /// </summary>
        static LocalLoggingFile()
        {
            // 确保基础目录存在
            if (!Directory.Exists(basePath))
            {
                Directory.CreateDirectory(basePath);
            }

            Task.Factory.StartNew(() => ProcessLogQueue(cts.Token), TaskCreationOptions.LongRunning);
        }

        /// <summary>
        /// 后台处理日志队列
        /// </summary>
        private static async Task ProcessLogQueue(CancellationToken token)
        {
            Interlocked.Increment(ref activeConsumers);
            var batchLogs = new List<LogEntry>(100);
            var lastFlushTime = DateTime.Now;

            try
            {
                while (isProcessing && !token.IsCancellationRequested)
                {
                    try
                    {
                        bool hasItems = false;

                        // 尝试取出所有可用日志
                        while (logQueue.TryDequeue(out var logEntry))
                        {
                            batchLogs.Add(logEntry);
                            hasItems = true;

                            if (batchLogs.Count >= 100)
                            {
                                break; // 批量大小限制
                            }
                        }

                        // 检查是否需要刷新
                        bool shouldFlush = batchLogs.Count > 0 &&
                                          (batchLogs.Count >= 100 ||
                                           (DateTime.Now - lastFlushTime).TotalSeconds >= 3);

                        if (shouldFlush)
                        {
                            await ProcessBatch(batchLogs);
                            batchLogs.Clear();
                            lastFlushTime = DateTime.Now;
                            hasItems = false;
                        }

                        // 如果没有日志需要处理，等待信号
                        if (!hasItems)
                        {
                            // 等待日志信号或超时
                            await logSignal.WaitAsync(TimeSpan.FromSeconds(1), token);
                        }
                    }
                    catch (OperationCanceledException) when (token.IsCancellationRequested)
                    {
                        break; // 正常退出
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"日志处理错误: {ex.Message}");
                        await Task.Delay(1000, token);
                    }
                }

                // 退出前处理剩余日志
                if (batchLogs.Count > 0)
                {
                    await ProcessBatch(batchLogs);
                }
            }
            finally
            {
                Interlocked.Decrement(ref activeConsumers);
            }
        }

        /// <summary>
        /// 处理批次日志
        /// </summary>
        private static async Task ProcessBatch(List<LogEntry> batchLogs)
        {
            if (batchLogs.Count == 0) return;
            // 按日志级别和日期分组处理
            var groupedLogs = batchLogs.GroupBy(x => new
            {
                Level = x.Level?.ToLower() ?? "info",
                Date = x.Timestamp.Date
            });

            foreach (var group in groupedLogs)
            {
                if (group.Key.Level == "pwid")
                {
                    await ProcessPwIdLogs(group.ToList());
                }
                else
                {
                    await ProcessNormalLogs(group.Key.Level, group.Key.Date, group.ToList());
                }
            }
        }

        /// <summary>
        /// 处理普通日志
        /// </summary>
        private static async Task ProcessNormalLogs(string level, DateTime date, List<LogEntry> logs)
        {
            if (logs.Count == 0) return;

            string logFile = Path.Combine(filePath, $"{date:yyyy-MM-dd}-{level}.log");
            var logContent = string.Join("", logs.Select(FormatLogEntry));

            await WriteToFileAsync(logFile, logContent);
        }

        /// <summary>
        /// 处理PWID日志（去重）
        /// </summary>
        private static async Task ProcessPwIdLogs(List<LogEntry> logs)
        {
            if (logs.Count == 0) return;

            var date = logs[0].Timestamp.Date;
            string logFile = Path.Combine(filePath, $"{date:yyyy-MM-dd}-pwid.log");

            // 过滤已存在的PWID
            var uniqueLogs = new List<LogEntry>();
            foreach (var log in logs)
            {
                if (pwIdInfo.TryAdd(log.Message, 0)) // 如果添加成功，说明是新的
                {
                    uniqueLogs.Add(log);
                }
            }

            if (uniqueLogs.Count > 0)
            {
                var logContent = string.Join("", uniqueLogs.Select(FormatLogEntry));
                await WriteToFileAsync(logFile, logContent);
            }
        }

        /// <summary>
        /// 异步写入文件（线程安全）
        /// </summary>
        private static async Task WriteToFileAsync(string filePath, string content)
        {
            try
            {
                // 确保目录存在
                var directory = Path.GetDirectoryName(filePath);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                // 使用文件锁确保线程安全
                using (var stream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.Read, 8192, true))
                using (var writer = new StreamWriter(stream))
                {
                    await writer.WriteAsync(content);
                    await writer.FlushAsync();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} 记录日志时出现异常，文件：{Path.GetFileName(filePath)}，异常信息：{ex.Message}");
            }
        }

        private static string FormatLogEntry(LogEntry entry)
        {
            if (entry.Level?.ToLower() == "pwid")
            {
                return $"{Environment.NewLine}{entry.Timestamp:yyyy-MM-dd HH:mm:ss} ----> {entry.Message}";
            }

            var exceptionText = entry.Exception != null ? $" --> {GetExceptionDetails(entry.Exception)}" : "";
            return $"{Environment.NewLine}{entry.Timestamp:yyyy-MM-dd HH:mm:ss} ----> {entry.Message}{exceptionText}";
        }

        private static string GetExceptionDetails(Exception ex)
        {
            if (ex == null) return string.Empty;
            return $"{ex.GetType().Name}: {ex.Message} | StackTrace: {ex.StackTrace}";
        }

        /// <summary>
        /// 添加日志到无限队列
        /// </summary>
        private static void AddLogToQueue(string message, string level, Exception e = null)
        {
            var logEntry = new LogEntry
            {
                Message = message,
                Level = level?.ToLower() ?? "info",
                Exception = e
            };

            logQueue.Enqueue(logEntry);

            // 在入队后释放信号
            try
            {
                logSignal.Release();
            }
            catch (ObjectDisposedException)
            {
                // 系统正在关闭，忽略
            }
        }

        /// <summary>
        /// 记录正常日志
        /// </summary>
        public static void Log(string message)
        {
            AddLogToQueue(message, "info");
        }

        /// <summary>
        /// 记录指定级别的日志
        /// </summary>
        public static void Log(string message, string level, Exception e = null)
        {
            AddLogToQueue(message, level, e);
        }

        /// <summary>
        /// 记录异常日志
        /// </summary>
        public static void ErrorLog(string message, Exception e = null)
        {
            AddLogToQueue(message, "error", e);
        }

        /// <summary>
        /// 记录PWID日志
        /// </summary>
        public static void LogPwId(string message)
        {
            AddLogToQueue(message, "pwid");
        }

        /// <summary>
        /// 获取队列状态
        /// </summary>
        public static (int QueueCount, int ActiveConsumers) GetStatus()
        {
            return (logQueue.Count, activeConsumers);
        }

        /// <summary>
        /// 优雅关闭日志系统
        /// </summary>
        public static void Shutdown(TimeSpan timeout)
        {
            isProcessing = false;
            cts.Cancel();

            // 唤醒所有消费者
            try
            {
                logSignal.Release(activeConsumers * 2);
            }
            catch { }

            // 等待消费者完成
            var startTime = DateTime.Now;
            while (activeConsumers > 0 && (DateTime.Now - startTime) < timeout)
            {
                Task.Delay(100);
            }

            cts.Dispose();
            logSignal.Dispose();
            Console.WriteLine($"{DateTime.Now} 日志写入完成：共写入{pwIdInfo.Count}条电站ID信息");
        }
    }
}
